package com.yeti.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.yeti.domain.Cliente;
import com.yeti.domain.Lista;
import com.yeti.domain.Producto;
import com.yeti.repository.ClienteDAO;
import com.yeti.repository.ListaDAO;
import com.yeti.repository.ProductoDAO;

@Component
public class ListaServiceImpl implements ListaService{
	
	@Autowired
	private ListaDAO listaDao;
	@Autowired
	private ClienteDAO clienteDao;
	@Autowired
	private ProductoDAO productoDao;
	
	private static int ITEMS_PER_PAGE = 10;

	/**
	 * Metodo que crea una nueva lista.
	 * 
	 * @param titulo: Es el nombre que tendrá la lista.
	 * @param username: Es el nombre de usuario del administrador de la lista.
	 */
	@Override
	@Transactional(readOnly = false)
	public void addLista(String titulo,String username) {
		Cliente cliente = clienteDao.getCliente(username);
		Lista lista = new Lista();
		lista.setNombre(titulo);
		lista.setAdministrador(cliente);
		lista.setFechaCreacion(new Date());
		listaDao.addLista(lista);
		cliente.addLista(lista);
		clienteDao.updateCliente(cliente);
	}

	/**
	 * Metodo que actualiza el nombre de una lista.
	 * 
	 * @param id: Es el id de la lista a actualizar.
	 * @param nombre: Es el nombre que tendrá la lista.
	 */
	@Override
	@Transactional(readOnly = false)
	public void updateLista(int id, String nombre) {
		Lista list = listaDao.getLista(id);
		list.setNombre(nombre);
		listaDao.updateLista(list);
	}

	/**
	 * Metodo que busca una lista por id.
	 * 
	 * @param id: Es el id de la lista a buscar.
	 * @return: Devuelve una lista dado un id.
	 */
	@Override
	@Transactional(readOnly = true)
	public Lista getLista(int id) {
		return listaDao.getLista(id);
	}

	/**
	 * Metodo que devuelve las listas de un usuario.
	 * 
	 * @param usernmae: Es el nombre del usuario del que se devolveran las listas.
	 * @param: Devuelve las listas del usuario.
	 */
	@Override
	@Transactional(readOnly = true)
	public List<Lista> getListas(String username) {
		return clienteDao.getCliente(username).getListas();
	}
	
	/**
	 * Metodo que obtiene las listas de un usuario paginado.
	 * 
	 * @param usernmae: Es el nombre de usuario del que se obtendran las listas.
	 * @param page: Es la página a devolver.
	 * @return: devuelve una lista de listas de la página pedida.
	 */
	@Override
	@Transactional(readOnly = true)
	public ArrayList<Object> getListas(String username,int page) {
		
		int min_index,max_index = 0;
		
		int totalPaginas = 1;
		
		ArrayList<Object> listas = new ArrayList<Object>();
		
		List<Lista> lista_paginada = clienteDao.getCliente(username).getListas();
		
		Collections.reverse(lista_paginada);
		
		int size = lista_paginada.size();
		
		min_index = (page-1) * ITEMS_PER_PAGE;
		max_index = page * ITEMS_PER_PAGE;
		
		if(min_index>=size){
			return null;
		}
		
		if(max_index>size){
			max_index = size;
		}
		
		listas.add(0, lista_paginada.subList(min_index, max_index));
		
		totalPaginas = size/ITEMS_PER_PAGE;
		
		if(size%ITEMS_PER_PAGE!=0){
			totalPaginas++;
		}
		
		listas.add(1, totalPaginas);
		
		return listas;
	}

	/**
	 * Metodo que quita una lista a un usuario.
	 * 
	 * @param id: Es el id de la lista a quitar.
	 * @param username: Es el usuario del cual quitaremos la lista.
	 */
	@Override
	@Transactional(readOnly = false)
	public void removeLista(int id, String username) {
		try{
			Cliente c = clienteDao.getCliente(username);
			Lista l = listaDao.getLista(id);
			if(c.getId()==l.getAdministrador().getId()){
				listaDao.remLista(l);
			}else{
				c.removeLista(l);
			}
		}catch(Exception e){
			System.out.println(e);
		}
	}
	

		/**
	 * Metodo que quita una lista a un usuario.
	 * 
	 * @param id: Es el id de la lista a quitar.
	 * @param idAmigo: Es el usuario del cual lo quitaremos de la lista.
	 */
	@Override
	@Transactional(readOnly = false)
	public void removeAmigo(int idLista, int idAmigo) {
		try{
			Lista l = listaDao.getLista(idLista);
			for(Cliente g: l.getGestores()){
				if(g.getId() == idAmigo){
					l.removeGestor(g);
				}
			}
		}catch(Exception e){
			System.out.println(e);
		}
	}
	
	/**
	 * Metodo que añade un producto a una lista.
	 * 
	 * @param id: Es el id de la lista a añadir el producto.
	 * @param nombre: Es el nombre del producto.
	 * @param cantidad: Es la cantidad de unidades del producto.
	 * @param precio: Es el precio del producto.
	 * @return: Devuelve true si la operación finaliza correctamente, false en caso contrario.
	 */
	@Override
	@Transactional(readOnly = false)
	public boolean addProducto(int id, String nombre, int cantidad, float precio){
		Lista l = listaDao.getLista(id);
		
		Producto p = new Producto();
		p.setNombre(nombre);
		p.setCantidad(cantidad);
		p.setPrecio(precio);
		l.setProducto(p);
		productoDao.addProducto(p);
		return true;
	}
	
	/**
	 * Metodo que actualiza un producto de una lista.
	 * 
	 * @param idLista: Es el id de la lista de donde procede el producto.
	 * @param idProducto: Es el id del producto a actualizar.
	 * @param nombre: Es el nuevo nombre del producto.
	 * @param cantidad: Es la nueva cantidad del producto.
	 * @param precio: Es el nuevo precio.
	 * @return: Devuelve true en caso de que la operación se produzca con éxito, false en caso contrario.
	 */
	@Override
	@Transactional(readOnly = false)
	public boolean updateProducto(int idLista, int idProducto, String nombre, int cantidad, float precio){
		Lista l = listaDao.getLista(idLista);
		Producto p = productoDao.getProducto(idProducto);
		if(l.getProductos().contains(p)){
			p.setNombre(nombre);
			p.setCantidad(cantidad);
			p.setPrecio(precio);
			productoDao.updateProducto(p);
			return true;
		}else{
			return false;
		}
	}

	/**
	 * Metodo que elimina un producto de la lista.
	 * 
	 * @param idLista: Es el id de la lista de donde se eliminará el producto.
	 * @param idProducto: Es el id del producto a eliminar.
	 */
	@Override
	@Transactional(readOnly = false)
	public void removeProducto(int idLista, int idProducto) {
		Lista l = listaDao.getLista(idLista);
		Producto p = productoDao.getProducto(idProducto);
		if(l.getProductos().contains(p)){
			l.removeProducto(p);
			productoDao.remProducto(p);
		}
	}

	/**
	 * Metodo que devuelve todos los amigos que se pueden seleccionar de esa lista.
	 * 
	 * @param idLista: Es el id de la lista de la cual se realizara el calculo.
	 * @return: Devuelve una lista con todos los usuarios seleccionables.
	 */
	@Override
	@Transactional(readOnly=true)
	public List<Cliente> getListaAmigosSeleccionables(int listaId) {
		Lista lista = listaDao.getLista(listaId);
		List<Cliente> clientes = clienteDao.getClientes(); 

		for(Cliente c : lista.getGestores()){
			clientes.remove(c);
		}
		return clientes;
	}



	/**
	 * Metodo que devuelve todos los amigos que pertenecen a una lista menos el mismo.
	 * 
	 * @param idLista: Es el id de la lista de la cual se realizara el calculo.
	 * @param username:Es el username del que realiza la accion para no cogerlo entre los gestores
	 * @return: Devuelve una lista con todos los usuarios seleccionables.
	 */
	@Override
	@Transactional(readOnly=true)
	public List<Cliente> getAmigosInLista(int listaId, String username) {
		Lista lista = listaDao.getLista(listaId);
		Cliente clienteActual = clienteDao.getCliente(username);
		List<Cliente> clientes = lista.getGestores();
	
		clientes.remove(clienteActual);
	
		return clientes;
	}
	
	/**
	 * Metodo que añade un amigo en una lista.
	 * 
	 * @param idLista: Es el id de la lista de la cual se realizara la adicion.
	 * @param idAmigo: Es el id del cliente que se introducira en los gestores de la lista
	 * @return: Devuelve una lista con todos los usuarios seleccionables.
	 */
	@Override
	@Transactional(readOnly=false)
	public boolean addAmigo(int listaId, int idAmigo) {
		Lista lista = listaDao.getLista(listaId);
		Cliente clienteActual = clienteDao.getCliente(idAmigo);
		lista.setGestor(clienteActual);
		//listaDao.updateLista(lista);
		
		return true;
	}

}
